package com.conversationboard.api;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.SecurityContext;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.conversationboard.api.formatters.XmlDateFormatter;
import com.conversationboard.api.formatters.XmlWrapper;
import com.conversationboard.api.xml.ApiXPath;
import com.conversationboard.api.xml.XmlUtils;
import com.conversationboard.cache.newanswers.NewAnswersThread;
import com.conversationboard.model.Board;
import com.conversationboard.model.Boards;
import com.conversationboard.model.User;
import com.conversationboard.site.Site;

/* Format: <Threads><BoardId>40</BoardId></Threads> */

/* Site new answers: <Threads></Threads> */

//TODO: doesn't work if the # new answers isn't 200 (or what's set in config)

public class RecentlyUpdatedThreadsProcessor implements Processor {

	private static XPathExpression boardIdExpression;

	static {
		try {
			boardIdExpression = ApiXPath.getXPath().compile("/Requests/RecentlyUpdatedThreads/BoardId/text()");
		} catch (XPathExpressionException e) {
		}
	}


	@Override
	public String processXml(String xml, SecurityContext securityContext, HttpServletRequest request) throws ApiException {

		StringBuilder buffer = new StringBuilder();

		try {
			User user = User.get(request.getUserPrincipal());

			Document document = XmlUtils.getDocument(xml);
			int boardId = Integer.parseInt((String) boardIdExpression.evaluate(document, XPathConstants.STRING));

			List<NewAnswersThread> threads;

			/* a board ID of 0 indicates you want Site New Posts */
			if (boardId == 0) {
				threads = Site.getSiteNewAnswers().getAllThreads();
			} else {
				Board board = Boards.getBoard(boardId);
				threads = board.getThreadsWithNewAnswers();
			}

			int numberOfNewAnswers = 200;

			buffer.append("<RecentlyUpdatedThreads>");
			buffer.append("<TotalMessages>" + threads.size() + "</TotalMessages>");
			
			if (boardId != 0) {
				Board board = Boards.getBoard(boardId);
				buffer.append("<BoardName>" + board.getName() + "</BoardName>");
				buffer.append("<BoardId>" + board.getBoardId() + "</BoardId>");
			} else {
				buffer.append("<BoardName>Site New Posts</BoardName>");
				buffer.append("<BoardId>0</BoardId>");
			}

			if (numberOfNewAnswers > 0) {
				buffer.append("<DisplayingLast>" + numberOfNewAnswers + "</DisplayingLast>");
			}

			int i = 0;

			for (NewAnswersThread thread : threads) {

				if ((numberOfNewAnswers > 0) && (i++ + numberOfNewAnswers < threads.size())) {
					continue;
				}

				/* Check that the user can read the thread being displayed */

				if (!user.canRead(thread.getBoardId())) {
					continue;
				}

				/* Force the format of dates to a standard form */

				String lastUpdatedString = XmlDateFormatter.format(thread.getLastUpdated());
				String createdOnString = XmlDateFormatter.format(thread.getTimestamp());

				buffer.append("<Thread>");
				buffer.append(XmlWrapper.wrap("BoardId", thread.getBoardId() + ""));
				buffer.append(XmlWrapper.wrap("ThreadId", thread.getThreadId() + ""));
				buffer.append(XmlWrapper.wrapCDATA("Title", thread.getTitle()));
				buffer.append(XmlWrapper.wrap("CreatedOn", createdOnString));
				buffer.append(XmlWrapper.wrap("LastUpdated", lastUpdatedString));
				buffer.append(XmlWrapper.wrap("Deleted", XmlWrapper.convertBoolean(thread.isDeleted())));
				buffer.append(XmlWrapper.wrap("Worksafe", XmlWrapper.convertBoolean(thread.isWorksafe())));
				buffer.append(XmlWrapper.wrap("Locked", XmlWrapper.convertBoolean(thread.isLocked())));
				buffer.append(XmlWrapper.wrap("Poll", XmlWrapper.convertBoolean(thread.isPoll())));
				buffer.append("</Thread>");
			}

			buffer.append("</RecentlyUpdatedThreads>");

		} catch (NumberFormatException e) {
			throw new ApiException(e);
		} catch (XPathExpressionException e) {
			throw new ApiException(e);
		} catch (ParserConfigurationException e) {
			throw new ApiException(e);
		} catch (IOException e) {
			throw new ApiException(e);
		} catch (SAXException e) {
			throw new ApiException(e);
		} catch (SQLException e) {
			throw new ApiException(e);
		}

		return buffer.toString();
	}

}
